using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Custom.Daily.Toolkit
{
    /// <summary>
    /// 自定义单例
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public abstract class Singleton<T> : SerializedMonoBehaviour where T : Singleton<T>
    {
        private static T instance = null;
        private static readonly object lockObj = new object();
        protected virtual bool isDontDestroyOnLoad => false;

        protected virtual void Awake()
        {
            // 确保单例的唯一性
            if (instance != null && instance != this)
            {
                Destroy(gameObject);
                return;
            }
            instance = this as T;
            if (isDontDestroyOnLoad)
            {
                DontDestroyOnLoad(gameObject);
            }
            // 监听场景加载事件
            SceneManager.sceneLoaded += OnSceneLoaded;
        }

        private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            // 检查场景中是否有多余的单例对象
            T[] instances = FindObjectsOfType<T>();
            if (instances.Length > 1)
            {
                for (int i = 0; i < instances.Length; i++)
                {
                    if (instances[i] != instance)
                    {
                        Destroy(instances[i].gameObject);
                    }
                }
            }
        }

        #region 接口
        /// <summary>
        /// 切换场景时不要销毁
        /// </summary>
        public void SetInstanceNotDestroy()
        {
            if (instance == null)
            {
                Debug.LogWarning($"{typeof(T).Name}:单例不存在!");
                return;
            }
            SetNotDestroy();
        }

        /// <summary>
        /// 获取单例对象
        /// </summary>
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockObj)
                    {
                        if (instance == null && !CheckObjectInScene())
                        {
                            // 创建一个新的单例对象
                            CreateSingletonObject();
                        }
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// 指定预制体对象的单例
        /// </summary>
        /// <param name="prefabsPath">Resources 目录下预制件路径</param>
        /// <param name="isDestroy">切换场景是否保留</param>
        public static void InitInstance(string prefabsPath, bool isDestroy = false)
        {
            if (instance == null)
            {
                lock (lockObj)
                {
                    if (instance != null || CheckObjectInScene())
                    {
                        Debug.LogWarning($"{typeof(T).Name}:单例已经存在,不能指定预制体创建单例!");
                        return;
                    }

                    string instanceName = typeof(T).Name;
                    GameObject instanceGO = GameObject.Find(instanceName);

                    if (instanceGO == null)
                    {
                        GameObject prefab = Resources.Load<GameObject>(prefabsPath);
                        if (prefab == null)
                        {
                            Debug.LogWarning($"指定单例预制体不存在!:{prefabsPath}");
                            return;
                        }
                        instanceGO = Instantiate(prefab);
                        // 设置实例化对象的名字
                        instanceGO.name = instanceName;
                    }
                    instance = instanceGO.GetComponent<T>();
                    // 切换场景时是否会销毁对象
                    if (!isDestroy)
                        SetNotDestroy();
                }
            }
        }

        protected virtual void OnDestroy()
        {
            instance = null;
            // 取消监听场景加载事件
            SceneManager.sceneLoaded -= OnSceneLoaded;
        }
        #endregion

        #region 私有方法
        private static bool CheckObjectInScene()
        {
            instance = FindObjectOfType<T>();

            if (instance != null)
            {
                if (FindObjectsOfType<T>().Length > 1)
                {
                    Debug.LogWarning($"{typeof(T).Name}:单例对象个数大于1!");
                    return true;
                }
                return true;
            }
            return false;
        }

        private static void CreateSingletonObject()
        {
            string instanceName = typeof(T).Name;
            GameObject instanceGO = new GameObject(instanceName);
            instance = instanceGO.AddComponent<T>();
            SetNotDestroy();
        }

        private static void SetNotDestroy()
        {
            if (instance != null)
                DontDestroyOnLoad(instance.gameObject);
            else
                Debug.LogWarning($"{typeof(T).Name}:单例对象为空!");
        }
        #endregion
    }
}
